package com.wh1200.mybatis.xmlless.resolver

import com.wh1200.mybatis.xmlless.config.BaseResolverTest
import com.wh1200.mybatis.xmlless.enums.MethodType
import com.wh1200.mybatis.xmlless.model.Properties
import com.wh1200.mybatis.xmlless.model.TableName
import com.wh1200.xmlless.test.dao.StudentDAO
import com.wh1200.xmlless.test.dao.StudentDetailDAO
import com.wh1200.xmlless.test.model.Student
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import kotlin.reflect.jvm.javaMethod
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertNotNull

/**
 * Created by 吴昊 on 2023/12/14.
 */
@DisplayName("方法名称解析器测试")
class NameResolverTest : BaseResolverTest(StudentDAO::class.java) {

  @Test
  @DisplayName("解析findAll")
  fun resolveFindAll() {
    val methodInfo = createMethodInfo(StudentDAO::findAll.javaMethod!!)
    val result = NameResolver(methodInfo).resolve()
    assertEquals(MethodType.Select, result.queryType)
    assert(result.properties.isEmpty())
    // 存在逻辑删除的条件
    assert(result.conditions.size == 1)
    assert(result.excludeProperties.isEmpty())
  }

  @Test
  fun findAllPage() {
    val method = StudentDAO::findAllPage.javaMethod!!
    val methodInfo = createMethodInfo(method)
    val query = createQueryForMethod(method)
    assertNotNull(query.sql)
    assertNotNull(query.query)
    val includedTableAlias = query.query!!.containedTables()
    val tablesFromColumns = ColumnsResolver.resolveIncludedTables(Properties(), methodInfo)
        .distinct()
    val allJoins = mappings.selectJoins(
        1,
        includedTableAlias,
        null,
        null,
        true
    )
    val subJoins = mappings.selectJoins(
        2,
        includedTableAlias,
        TableName("t_score", "id_t_score"),
        null,
        true
    )
    assert(includedTableAlias.contains("id_t_score_subject_id_subject"))
  }

  @Test
  @DisplayName("从SelectedProperties注解中获取指定的字段")
  fun resolveUpdatePartly() {
    val methodInfo = createMethodInfo(StudentDAO::updatePartly.javaMethod!!)
    val result = NameResolver(methodInfo).resolve()
    assertEquals(MethodType.Update, result.queryType)
    assert(result.properties.isEmpty())
    assert(result.conditions.isEmpty())
    assert(result.excludeProperties.isEmpty())
  }

  @Test
  @DisplayName("从方法名称中解析要返回的字段")
  fun resolvePropertyInName() {
    val result2 = NameResolver(
        createMethodInfo(StudentDetailDAO::findEducation.javaMethod!!)
    ).resolve()
    assertEquals(result2.properties, listOf("education"))
  }

  @Test
  @DisplayName("解析单个条件")
  fun reolsveSingleCriteriaFromName() {
    val result = NameResolver(
        createMethodInfo(StudentDAO::findById.javaMethod!!)
    ).resolve()
    // 含逻辑删除的条件，所以有两个条件
    assertEquals(2, result.conditions.size)
  }

  @Test
  @DisplayName("解析属性和条件")
  fun resolvePropertiesAndCriteriaFromName() {
    val result = NameResolver(
        createMethodInfo(StudentDAO::updateNameById.javaMethod!!)
    ).resolve()
    assertEquals(result.properties, listOf("name"))
    assertEquals(1, result.conditions.size)
    val q = createQueryForMethod(StudentDAO::updateNameById.javaMethod!!)
    assertNotNull(q.sql)
  }

  @Test
  fun test() {
    val q = createQueryForMethod(StudentDAO::findByStateIn.javaMethod!!)
    assertNotNull(q.sql)
  }

  @Test
  @DisplayName("解析Group By")
  fun resolveGroupBy() {
    val result = NameResolver(
        createMethodInfo(StudentDAO::findCountAndGradeGroupByGrade.javaMethod!!)
    ).resolve()
    assertEquals(2, result.properties.size)
    assertContains(result.properties, "count")
    assertContains(result.properties, "grade")
    assertEquals(1, result.groupBy.size)
    assertEquals("grade", result.groupBy.first())
  }

  @Test
  @DisplayName("解析Having")
  fun resolveHaving() {
    val result = NameResolver(
        createMethodInfo(StudentDAO::findCountAndGradeGroupByGradeHavingCountGt1.javaMethod!!)
    ).resolve()
    assertEquals(2, result.properties.size)
    assertContains(result.properties, "count")
    assertContains(result.properties, "grade")
    assertEquals(1, result.groupBy.size)
    assertEquals("grade", result.groupBy.first())
    assertEquals(1, result.havingConditions.size)
    assertEquals("count(*) &gt; 1 AND", result.havingConditions[0].toSqlWithoutTest())
  }

  @Test
  @DisplayName("解析is not null")
  fun resolveIsNotNull() {
    val result = NameResolver(
        createMethodInfo(StudentDAO::find3.javaMethod!!)
    ).resolve()
    assertEquals("t_student.birthday IS NOT NULL AND", result.conditions.first().toString())
  }

}
